package com.gzx.plugin.tjzy.modular.call.ht.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.gzx.plugin.tjzy.modular.call.ht.entity.GzxHtCallRecord;
import com.gzx.plugin.tjzy.modular.call.ht.properties.CallInProperties;
import com.gzx.plugin.tjzy.modular.call.ht.service.GzxHtCallAsyncUpdateRecordService;
import com.gzx.plugin.tjzy.modular.call.ht.service.GzxHtCallRecordService;
import com.gzx.plugin.tjzy.modular.call.pre.entity.GzxPreOutCallDetail;
import com.gzx.plugin.tjzy.modular.call.pre.service.GzxPreOutCallService;
import com.gzx.plugin.tjzy.modular.gzxcase.entity.GzxCase;
import com.gzx.plugin.tjzy.modular.gzxcase.service.GzxCaseDbService;
import com.gzx.plugin.tjzy.modular.liaison.entity.GzxDebtorLiaison;
import com.gzx.plugin.tjzy.modular.liaison.service.GzxDebtorLiaisonService;
import com.gzx.plugin.tjzy.modular.work.entity.GzxMediatorWork;
import com.gzx.plugin.tjzy.modular.work.service.GzxMediatorWorkService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import vip.xiaonuo.common.tenant.TenantContext;
import vip.xiaonuo.common.util.CommonCryptogramUtil;
import vip.xiaonuo.common.util.CommonDateUtil;
import vip.xiaonuo.sys.feign.SysUserFeign;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author zjt
 * @description
 * @date 2025/1/3 11:00
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GzxHtCallAsyncUpdateRecordServiceImpl implements GzxHtCallAsyncUpdateRecordService {

    private final GzxHtCallRecordService htCallRecordService;

    private final GzxPreOutCallService preOutCallService;

    private final GzxCaseDbService caseDbService;

    private final GzxDebtorLiaisonService debtorLiaisonService;

    private final GzxMediatorWorkService mediatorWorkService;

    private final RedissonClient redissonClient;

    private final SysUserFeign userFeign;

    private final CallInProperties callInProperties;

    @Override
    public void asyncUpdateRecord(List<ConsumerRecord<String, String>> recordList) {
        //保存到数据库
        List<GzxHtCallRecord> htCallRecordList = getHtCallRecordList(recordList);
        //查询预测外呼明细数据
        Set<String> preOutIdList = htCallRecordList.stream().filter(row -> row.getCallType() == 2)
                .map(GzxHtCallRecord::getBusiness)
                .filter(StringUtils::isNotEmpty)
                .collect(Collectors.toSet());
        try {
            TenantContext.disableTenantFilter();
            Map<String, JSONObject> userMap = getUserMap(htCallRecordList.stream().map(GzxHtCallRecord::getAgentNum).filter(StringUtils::isNotEmpty).collect(Collectors.toSet()));
            Map<String, GzxPreOutCallDetail> preOutCallDetailMap = getPreOutDetailMap(preOutIdList);
            Set<String> caseIdSet = htCallRecordList.stream().filter(row -> row.getCallType() == 1)
                    .map(GzxHtCallRecord::getBusiness)
                    .filter(StringUtils::isNotEmpty)
                    .collect(Collectors.toSet());
            Map<String, GzxCase> caseMap = getCaseMap(caseIdSet);
            Map<String, GzxHtCallRecord> htPreCallRecordMap = new HashMap<>();
            Map<Long, GzxHtCallRecord> caseIdMap = new HashMap<>();
            for (GzxHtCallRecord htCallRecord : htCallRecordList) {
                //设置租户ID和部门ID
                try {
                    if (StringUtils.isNotEmpty(htCallRecord.getAgentNum()) && userMap.containsKey(htCallRecord.getAgentNum())) {
                        JSONObject user = userMap.get(htCallRecord.getAgentNum());
                        htCallRecord.setDeptId(user.getString("orgId"));
                        htCallRecord.setTenantId(user.getString("tenantId"));
                    } else {
                        Map<String, String> properties = callInProperties.getTenantIdAndDeptIdByCallee(CommonCryptogramUtil.doSm1AesDecrypt(htCallRecord.getCallee()));
                        if (CollectionUtil.isNotEmpty(properties)) {
                            htCallRecord.setDeptId(properties.get("deptId"));
                            htCallRecord.setTenantId(properties.get("tenantId"));
                        }
                    }
                } catch (Exception e) {
                    log.error("话单回传，获取租户ID和部门ID出现异常", e);
                }
                if (StringUtils.isNotEmpty(htCallRecord.getBusiness())) {
                    //单点外呼
                    if (htCallRecord.getCallType() == 1 && StringUtils.isNotEmpty(htCallRecord.getBusiness())) {
                        if (CollectionUtil.isNotEmpty(caseMap) && caseMap.containsKey(htCallRecord.getBusiness())) {
                            singleParamByCase(caseMap, htCallRecord);
                        } else {
                            htCallRecord.setTenantId(htCallRecord.getBusiness());
                        }
                    }
                    //预测外呼，并且DetailId存在
                    if (htCallRecord.getCallType() == 2 && CollectionUtil.isNotEmpty(preOutCallDetailMap) && preOutCallDetailMap.containsKey(htCallRecord.getBusiness())) {
                        GzxPreOutCallDetail preOutCallDetail = preOutCallDetailMap.get(htCallRecord.getBusiness());
                        htCallRecord.setCaseId(preOutCallDetail.getCaseId());
                        htCallRecord.setTenantId(preOutCallDetail.getTenantId());
                        htPreCallRecordMap.put(String.valueOf(preOutCallDetail.getId()), htCallRecord);
                        if (htCallRecord.getCallDuration() <= 0) {
                            //map中，long为案件的主键自增id，String为 htCallRecord.getCallee()，自动给预外呼未接听的电话记录催记
                            caseIdMap.put(htCallRecord.getCaseId(), htCallRecord);
                        }
                    }
                }
            }
            //批量新增作业记录
            addMediatorWorks(caseIdMap);
            updatePreCallDetail(htPreCallRecordMap);//批量更新预外呼明细
        } catch (Exception e) {
            log.error("更新预测外呼明细出现异常:{}", e.getMessage());
        } finally {
            try {
                htCallRecordService.asyncInsertRecord(htCallRecordList);//批量插入话单记录
            } catch (Exception e) {
                log.error("批量保存话单记录失败!", e);
            }
            TenantContext.enableTenantFilter();
            TenantContext.clear();
        }
    }

    private List<GzxHtCallRecord> getHtCallRecordList(List<ConsumerRecord<String, String>> recordList) {
        String currentDate = CommonDateUtil.getCurrentTimeStr();
        List<GzxHtCallRecord> htCallRecordList = new ArrayList<>();
        for (ConsumerRecord<String, String> record : recordList) {
            GzxHtCallRecord htCallRecord = JSON.parseObject(record.value(), GzxHtCallRecord.class);
            htCallRecord.setCreatedTime(currentDate);
            htCallRecord.setCallee(CommonCryptogramUtil.doSm1AesEncrypt(htCallRecord.getCallee()));
            htCallRecordList.add(htCallRecord);
        }
        return htCallRecordList;
    }

    private Map<String, JSONObject> getUserMap(Set<String> agentNum) {
        Map<String, JSONObject> userMap = new HashMap<>();
        try {
            JSONArray jsonArray = JSONArray.parseArray(userFeign.getUserByAccount(agentNum));
            for (int i = 0; i < jsonArray.size(); i++) {
                String value = jsonArray.getString(i);
                JSONObject jsonObject = JSON.parseObject(value);
                userMap.put(jsonObject.getString("account"), jsonObject);
            }
        } catch (Exception e) {
            log.error("回传的话单，解析用户失败", e);
        }
        return userMap;
    }

    private Map<String, GzxPreOutCallDetail> getPreOutDetailMap(Set<String> preOutIdList) {
        if (CollectionUtil.isEmpty(preOutIdList)) {
            return Collections.emptyMap();
        }
        List<GzxPreOutCallDetail> preOutCallDetailList = preOutCallService.selectBatchIds(preOutIdList);
        if (CollectionUtil.isNotEmpty(preOutCallDetailList)) {
            return preOutCallDetailList.stream()
                    .collect(Collectors.toMap(
                            s -> String.valueOf(s.getId()),
                            Function.identity(),
                            (existing, replacement) -> replacement));
        }
        return Collections.emptyMap();
    }

    private Map<String, GzxCase> getCaseMap(Set<String> caseIdSet) {
        if (CollectionUtil.isEmpty(caseIdSet)) {
            return Collections.emptyMap();
        }
        List<GzxCase> caseList = caseDbService.selectCaseList(Wrappers.<GzxCase>lambdaQuery().in(GzxCase::getId, caseIdSet));
        if (CollectionUtil.isNotEmpty(caseList)) {
            return caseList.stream()
                    .collect(Collectors.toMap(
                            s -> String.valueOf(s.getId()),
                            Function.identity(),
                            (existing, replacement) -> replacement));
        }
        return Collections.emptyMap();
    }

    /**
     * 单点外呼根据案件信息补全案件ID和租户ID
     *
     * @param caseMap
     * @param htCallRecord
     */
    private void singleParamByCase(Map<String, GzxCase> caseMap, GzxHtCallRecord htCallRecord) {
        if (caseMap.containsKey(htCallRecord.getBusiness())) {
            GzxCase gzxCase = caseMap.get(htCallRecord.getBusiness());
            htCallRecord.setCaseId(gzxCase.getId());
            htCallRecord.setTenantId(gzxCase.getTenantId());
        } else {
            htCallRecord.setTenantId(htCallRecord.getBusiness());
        }
    }

    public void addMediatorWorks(Map<Long, GzxHtCallRecord> caseIdMap) {
        if (CollectionUtils.isEmpty(caseIdMap)) {
            return;
        }
        List<GzxCase> caseList = caseDbService.selectCaseList(Wrappers.<GzxCase>lambdaQuery().in(GzxCase::getId, caseIdMap.keySet()));
        if (!CollectionUtils.isEmpty(caseList)) {
            List<GzxMediatorWork> mediatorWorkList = new ArrayList<>();
            Date currentTime = new Date();
            for (GzxCase gzxCase : caseList) {
                GzxMediatorWork mediatorWork = new GzxMediatorWork();
                mediatorWork.setCaseId(gzxCase.getId());
                mediatorWork.setDebtorCardId(gzxCase.getDebtorCardId());
                mediatorWork.setProjectCode(gzxCase.getProjectCode());
                mediatorWork.setLiaisonPhone(CommonCryptogramUtil.doSm1AesDecrypt(caseIdMap.get(gzxCase.getId()).getCallee()));
                mediatorWork.setWorkType(2);
                mediatorWork.setWorkResult(2);
                List<GzxDebtorLiaison> debtorLiaisonList = debtorLiaisonService.selectList(Wrappers.<GzxDebtorLiaison>lambdaQuery()
                        .select(GzxDebtorLiaison::getLiaisonName)
                        .select(GzxDebtorLiaison::getRelationship)
                        .select(GzxDebtorLiaison::getPhoneSource)
                        .eq(GzxDebtorLiaison::getDebtorCardId, gzxCase.getDebtorCardId())
                        .eq(GzxDebtorLiaison::getLiaisonPhone, caseIdMap.get(gzxCase.getId()).getCallee())
                        .eq(GzxDebtorLiaison::getTenantId, gzxCase.getTenantId()));
                mediatorWork.setPhoneSource(0);
                if (CollectionUtil.isNotEmpty(debtorLiaisonList)) {
                    GzxDebtorLiaison debtorLiaison = debtorLiaisonList.get(0);
                    mediatorWork.setLiaisonName(debtorLiaison.getLiaisonName());
                    mediatorWork.setCallRecipient(debtorLiaison.getRelationship());
                    mediatorWork.setPhoneSource(debtorLiaison.getPhoneSource());
                }
                mediatorWork.setTenantId(gzxCase.getTenantId());
                mediatorWork.setCreateUser(String.valueOf(gzxCase.getMediatorId()));
                mediatorWork.setCreateTime(currentTime);
                mediatorWorkList.add(mediatorWork);
            }
            try {
                if (!CollectionUtils.isEmpty(mediatorWorkList)) {
                    //批量插入作业记录
                    mediatorWorkService.insertBatch(mediatorWorkList);
                }
            } catch (Exception e) {
                log.error("批量保存作业记录失败!", e);
            }
        }
    }

    public void updatePreCallDetail(Map<String, GzxHtCallRecord> htCallRecordMap) {
        if (CollectionUtils.isEmpty(htCallRecordMap)) {
            return;
        }
        List<GzxPreOutCallDetail> preOutCallDetailList = new ArrayList<>();
        List<GzxPreOutCallDetail> gzxPreOutCallDetails = preOutCallService.selectBatchIds(htCallRecordMap.keySet());
        if (!CollectionUtils.isEmpty(gzxPreOutCallDetails)) {
            log.info("开始更新预外呼明细及完成数量==========================：{}", gzxPreOutCallDetails.size());
            for (GzxPreOutCallDetail preOutCallDetail : gzxPreOutCallDetails) {
                GzxHtCallRecord htCallRecord = htCallRecordMap.get(String.valueOf(preOutCallDetail.getId()));
                if (htCallRecord != null) {
                    preOutCallDetail.setCallId(htCallRecord.getCallId());
                    preOutCallDetail.setRingTime(htCallRecord.getRingTime());
                    preOutCallDetail.setCallDuration(htCallRecord.getCallDuration());
                    preOutCallDetail.setSignal(htCallRecord.getSignal());
                    preOutCallDetailList.add(preOutCallDetail);
                    RLock rLock = null;
                    try {
                        rLock = redissonClient.getLock(preOutCallDetail.getBatchNumber());
                        // 使用tryLock 来防止死锁或锁获取失败
                        // 尝试获取锁，最多等待10秒，最多持有5秒
                        if (rLock.tryLock(10, 5, TimeUnit.SECONDS)) {
                            // 执行更新操作
                            preOutCallService.updatePreOutBatch(preOutCallDetail.getBatchNumber());
                        } else {
                            log.warn("无法获取到锁，batchNumber: {}", preOutCallDetail.getBatchNumber());
                        }
                    } catch (Exception e) {
                        log.error("获取分布式锁异常", e);
                    } finally {
                        if (rLock != null && rLock.isHeldByCurrentThread()) {
                            try {
                                rLock.unlock();
                            } catch (Exception e) {
                                log.error("释放锁异常", e);
                            }
                        }
                    }
                }
            }
        }
        try {
            preOutCallService.updateBatchByDetailId(preOutCallDetailList);
        } catch (Exception e) {
            log.error("批量更新预外呼明细记录失败!", e);
        }
    }
}
